﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using FlashCards.Dto;
using FlashCards.SL.FlashCardRepeater.Views;
using FlashCards.SL.FlashCardRepeater.ViewModels;
using System.Xml.Serialization;
using System.IO;
using FlashCards.SL.FlashCardRepeater.Utils;

namespace FlashCards.SL.FlashCardRepeater
{
    public partial class App : Application
    {
        private MainPage _mainPage;

        public static int UserId { get; private set; }
        public static int FlashcardSetId { get; private set; }
        public User CurrentUser { get; set; }
        public FlashcardSet CurrentFlashcardSet { get; set; }
        public List<RepeatItem> LastRepeats { get; set; }
        public string ApplicationMode { get; set; }
        public List<NetworkResult> LastNetworkResults { get; set; }

        public App()
        {
            this.Startup += this.Application_Startup;
            this.Exit += this.Application_Exit;
            this.UnhandledException += this.Application_UnhandledException;

            InitializeComponent();
        }

        public void LoadUserData(string dataString)
        {
            var serializer = new XmlSerializer(typeof(User));
            var reader = new StringReader(dataString);
            var user = serializer.Deserialize(reader) as User;

            CurrentUser = user;
        }

        public void LoadFlashcardData(string dataString)
        {
            var serializer = new XmlSerializer(typeof(FlashcardSet));
            var reader = new StringReader(dataString);
            var set = serializer.Deserialize(reader) as FlashcardSet;

            CurrentFlashcardSet = set;

            var dictionary = new AccentLettersUtils().GetAccentsForLanguage(CurrentFlashcardSet.Category.Language);
            if (!Application.Current.Resources.Contains("AccentsLettersDictionary"))
                Application.Current.Resources.Add("AccentsLettersDictionary", dictionary);
        }

        public void LoadFlashcardPartTypes(string dataString)
        {
            var serializer = new XmlSerializer(typeof(List<FlashcardPartType>));
            var reader = new StringReader(dataString);
            var types = serializer.Deserialize(reader) as List<FlashcardPartType>;

            if (types != null)
                Resources.Add("FlashcardPartTypes", types);
        }

        public void FinishDataLoading(EndRepeatEventArgs e)
        {
            if (e != null)
            {
                var tempLastRepeats = LastRepeats;
                LastRepeats = e.Repeat.Items;

                foreach (var item in tempLastRepeats)
                {
                    if (LastRepeats.FirstOrDefault(x => x.FlashcardId == item.FlashcardId) == null)
                        LastRepeats.Add(item);
                }
            }

            _mainPage.LayoutRoot.Children.Clear();

            var settingsModel = new RepeatSettingsViewModel(CurrentFlashcardSet, LastRepeats);
            settingsModel.OnConfigurationCompleted += settingsModel_OnConfigurationCompleted;
            var settingsView = new RepeatConfigurationView();
            settingsView.DataContext = settingsModel;
            _mainPage.LayoutRoot.Children.Add(settingsView);
        }

        void settingsModel_OnConfigurationCompleted(object sender, ConfigurationCompletedEventArgs e)
        {
            var setView = new FlashcardSetView();
            var setModel = new FlashcardSetViewModel(PrepareFlashcardSet(e.FlashcardsIds), UserId, e.FlashcardsSelectorType);

            setModel.OnEndRepeatCompleted += HandleEndRepeat;

            setView.DataContext = setModel;

            _mainPage.LayoutRoot.Children.Add(setView);
        }

        FlashcardSet PrepareFlashcardSet(List<int> flashcardsIds)
        {
            var flashcardSet = new FlashcardSet()
            {
                Category = CurrentFlashcardSet.Category,
                Creator = CurrentFlashcardSet.Creator,
                DateModified = CurrentFlashcardSet.DateModified,
                Id = CurrentFlashcardSet.Id,
                IsPublic = CurrentFlashcardSet.IsPublic,
                Name = CurrentFlashcardSet.Name,
                Tags = CurrentFlashcardSet.Tags,
                Flashcards = CurrentFlashcardSet.Flashcards.Where(x => flashcardsIds.Contains(x.Id)).ToList()
            };

            return flashcardSet;
        }

        void HandleEndRepeat(object sender, EndRepeatEventArgs e)
        {
            _mainPage.LayoutRoot.Children.Clear();

            var serviceEndpoint = string.Empty;

            if (ApplicationMode == "Production")
                serviceEndpoint = "Release_ISilverlightService";
            else if (ApplicationMode == "Development")
                serviceEndpoint = "Debug_ISilverlightService";

            var endRepeatView = new EndRepeatView();
            var endRepeatModel = new EndRepeatViewModel(e.Repeat, e.Set, serviceEndpoint);
            endRepeatModel.OnStartOverCompleted += (o, args) => FinishDataLoading(e);
            endRepeatView.DataContext = endRepeatModel;

            _mainPage.LayoutRoot.Children.Add(endRepeatView);
        }

        void HandleUserRepeatsLoadCompleted(object sender, DataLoadedEventArgs e)
        {
            if (!string.IsNullOrEmpty(e.SerializedString))
            {
                using (var reader = new StringReader(e.SerializedString))
                {
                    var serializer = new XmlSerializer(typeof(List<RepeatItem>));
                    var repeatItems = serializer.Deserialize(reader) as List<RepeatItem>;
                    if (repeatItems != null)
                    {
                        LastRepeats = repeatItems;
                    }
                }
            }
        }

        #region Event handlers

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            if (e.InitParams.ContainsKey("AppMode"))
            {
                ApplicationMode = e.InitParams["AppMode"];
            }

            if (e.InitParams.ContainsKey("UserID"))
            {
                UserId = int.Parse(e.InitParams["UserID"]);
            }
            if (e.InitParams.ContainsKey("FlashcardSetID"))
            {
                FlashcardSetId = int.Parse(e.InitParams["FlashcardSetID"]);
            }

            var serviceEndpoint = string.Empty;

            if (ApplicationMode == "Production")
                serviceEndpoint = "Release_ISilverlightService";
            else if (ApplicationMode == "Development")
                serviceEndpoint = "Debug_ISilverlightService";

            _mainPage = new MainPage();
            var loadingView = new LoadingView();
            var loadingModel = new LoadingViewModel(serviceEndpoint);
            loadingView.DataContext = loadingModel;
            loadingModel.UserRepeatsLoadCompleted += HandleUserRepeatsLoadCompleted;

            _mainPage.LayoutRoot.Children.Clear();
            _mainPage.LayoutRoot.Children.Add(loadingView);

            this.RootVisual = _mainPage;
        }

        private void Application_Exit(object sender, EventArgs e)
        {

        }

        #endregion

        #region Exceptions handling

        private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            // If the app is running outside of the debugger then report the exception using
            // the browser's exception mechanism. On IE this will display it a yellow alert 
            // icon in the status bar and Firefox will display a script error.
            if (!System.Diagnostics.Debugger.IsAttached)
            {

                // NOTE: This will allow the application to continue running after an exception has been thrown
                // but not handled. 
                // For production applications this error handling should be replaced with something that will 
                // report the error to the website and stop the application.
                e.Handled = true;
                Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); });
            }
        }

        private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e)
        {
            try
            {
                string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace;
                errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n");

                System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");");
            }
            catch (Exception)
            {
            }
        }

        #endregion
    }
}
